# 10.1.1
# 利用python打开文件

from pathlib import Path
"""
pi_string = ''
path = Path('pi_million_digits.txt')
contents = path.read_text()
# print(contents)
# lines = contents.splitlines()
for line in contents.splitlines():
    pi_string += line.lstrip()

print(f"{pi_string[:52]}")
print(len(pi_string))
"""

# 10.1.6
"""
birthday = input("Enter your birthday, in the form mmddyy: ")
if birthday in pi_string:
    print("Your birthday appears in the first million digits of pi!")
else:
    print("Your birthday does not appear in the first million digits of pi.")
"""

# 10.1后的动手试一试
# 练习10.1
"""
my_string_one = Path('learning_python.txt')
contents = my_string_one.read_text()
print(contents)

# lines = contents.splitlines()
for line in contents.splitlines():
    print(f'{line}')
"""

# 练习10.2
"""
my_string_one = Path('learning_python.txt')
contents = my_string_one.read_text()
print(contents)

# lines = contents.splitlines()
for line in contents.splitlines():
    new_line = line.replace('Python', 'C')
    print(f"{new_line}")
"""

# 10.2.1
# 在python中，对于int 型变量 和 char 型变量
# 由于在文本中出现的任何数据，如果采用read_text()方法
# 都会得到一个 char类型的数据
# 此时想要对文本中的数字进行数值运算时，先要使用函数int()
#
# python中只能将字符串写入文本文件，当使用write_text()方法时
# 如果要将数值数据存储到文本文件中，必须先使用函数str()将其转换为字符串格式
"""
path = Path('learning_python.txt')
path.write_text('I love programming.')
"""

# 10.2.2
# write_text()方法，会进行如下操作：
# 1、如果path变量对应的路径指向的文件不存在，就创建它
# 2、将字符串写入文件后，会确保文件得以妥善地关闭，
# 3、如果path变量对应的路径指向的文件已经存在，且该文件里已经有数据
#    就会把该文件原有的数据全部删除，写入新的文件
"""
contents = 'I love programming.\n'
contents += 'I love creating new games.\n'
contents += 'I also love working with data.\n'

path = Path('learning_python.txt')
path.write_text(contents)
"""

# 10.2后的动手试一试
# 练习10.4
"""
user_name = input("Please write down your name: ")
path = Path('guest.txt')
path.write_text(user_name)
"""

# 练习10.5
"""
user_names = ''
while True:
    print("If you want to quit this program, please enter 'q'.")
    user_name = input("Please write down a user's name: ")
    if user_name == 'q':
        break
    else:
        path = Path('guest_book.txt')
        user_names += (user_name + '\n')
        path.write_text(user_names)
"""

# 10.3.2
# 使用try-except代码块，先说明try-except代码块出现的必要性：
# 1、不使用try-except代码块时，python通过traceback 抛出异常
#    抛出异常会显示程序文件的名称，还将显示不能正确运行的代码
#    所以此时如果被黑客看到，可能会引起恶意攻击
# 2、使用try-except代码块后，可以跳过可能出错的代码，
#    继续执行try-except代码块后面的代码
# print(5/0)
try:
    print(5/0)
except ZeroDivisionError:
    print("You can not divide by zero!")

print("test!!!")

# 10.3.4
# try  except  else代码块的作用：
# try代码块中只包含可能使程序抛出异常的代码
# 如果在某次执行中try代码块只有部分代码成功执行
# 那么这些被成功执行的代码都会被放在else代码块中，
# 即：原先在else代码块的代码  只有在  try的成功执行的代码执行完毕后，才会执行
# except代码块告诉python，在出现ZeroDivisionError异常时该怎么办
"""
print("Give me two numbers, and I will divide them.")
print("Enter 'q' to quit.")
while True:
    first_number = input("\nFirst number: ")
    if first_number == 'q':
        break
    second_number = input("\nSecond number: ")
    if second_number == 'q':
        break

    try:
        answer = int(first_number) / int(second_number)
    except ZeroDivisionError:
        print("You can not divide by 0!")
    else:
        print(answer)
"""

# 10.3.5
# 当需要写try except 代码，但又不知道可能会报出什么样的错误时，
# 可以通过traceback的末尾出发，得到一个 异常 的名字

# 说明：
# split()方法默认以空白为分隔符将字符串分拆成多个部分
"""
path = Path('alice.txt')
try:
    contents = path.read_text(encoding='utf-8')
except FileNotFoundError:
    print(f"Sorry, the file {path} does not exist.")
else:
    words = contents.split()
    num_words = len(words)
    print(f"The file {path} has about {num_words} words.")
"""


# 10.3.7
"""
def count_words(path):
    try:
        contents = path.read_text(encoding='utf-8')
    except FileNotFoundError:
        print(f"Sorry, the file {path} does not exist.")
    else:
        words = contents.split()
        num_words = len(words)
        print(f"The file {path} has about {num_words} words.")


filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
    path = Path(filename)
    count_words(path)
"""

# 10.3后的动手试一试
# 练习10.7
# 注意：
# 1. 下面的程序不能由注释中的内容替代，这是因为：
#      1、下面的程序退出循环需要用户输入字符q，
#         但是如果直接将用户输入的q转换成整型，python将会直接抛出异常
#         不会进入try except模块
#      2、想利用try except模块，应该将可能出错的模块直接放在try后的模块中
#         所以此时应将int()转换语句放到try后的模块中
# 2. try except模块应该直接作为while循环的循环体的一部分，
#    这样才能堆每一次输入可能出现的一场进行反应
"""
print("Give me two numbers, I will add them.")
print("Please enter 'q' to quit.")

while True:
    # num_one = int(input('Please write down first number: '))
    num_one = input('Please write down first number: ')
    if num_one == 'q':
        break
    num_two = input('Please write down second number: ')
    # num_two = int(input('Please write down second number: '))
    if num_two == 'q':
        break
    try:
        num_first = int(num_one)
        num_second = int(num_two)
        answer = num_first + num_second

        # answer = num_one + num_two
    except ValueError:
        print(f"Sorry, at least one of numbers "
              f"that you have written down is not a number.\n")
    else:
        print(f"The result is {answer}.")
"""

# 练习10.8
"""
try:
    path_one = Path("cats.txt")
    contents_one = path_one.read_text()
    for content in contents_one.splitlines():
        print(content)

    path_two = Path("dogs.txt")
    contents_two = path_two.read_text()
    for content in contents_two.splitlines():
        print(content)
except FileNotFoundError:
    print(f"Sorry, the file does not exist!\n")
"""


# 练习10.10
# 对pathlib中Path这个模块的理解
# 1、Path这个函数的参数类型是 字符串类型
# 2、Path这个函数的返回值有两种属性，假设Path这个函数的返回值给一个名叫path的变量
#    1.path可以作为read_text()方法的对象，且path.read_text() 的结果是一个字符串
#    2.可以作为f""字符串的中打印字符串的一部分
"""
def count_special_words(content, str):
    return content.lower().count(f"{str}")


count = 0
filenames = ['alice.txt', 'siddhartha.txt', 'moby_dick.txt', 'little_women.txt']
for filename in filenames:
    try:
        path = Path(filename)
        content = path.read_text(encoding='utf-8')
    except FileNotFoundError:
        print(f"Sorry,the {path} does not exist.\n")
    else:
        info = f"Please write the string that you want to find in {filename}: "
        find_str = input(info)
        ret = count_special_words(content, find_str)
        print(f"There are {ret} {find_str} in {path}")
"""

# 10.4.1-1
# 使用json.dumps() 和 json.loads()，默认已经写入from pathlib import Path
# 下面的程序完成了：
#   1、创建一个数值列表，将列表中的数读取到内存中的程序
#   2、利用json.dumps()来存储这组数
#
# 实际上，json.dumps()和json.loads()就是python对象和json格式的数据 的链接通道
# 对于json.dumps()
# 注意：这不是一个方法，而是一个已经有确定对象的方法的调用
#   1、括号内写入一个python对象，
#      可以是dict，list，tuple，int,long,float，True,False，None
#   2、json.dumps()将把python对象翻译成JSON格式，
#      如果括号内传入的是dict类型的python对象，
#      则json.dumps()将返回JSON格式的字符串数据，

#      注意：这里仍然是字符串，也就是由数字，字母，下划线组成的一串字符，
#           但是利用write_text写到 以.json为后缀的 文件中，将被这个文件解读为json文件

# 对于write_text()方法
#   1、括号内写入字符串类型的数据
#   2、作用的对象(也就是点号 . 前的对象) 应是一个文件名，
#      但其对象的数据类型不应该是str，应该是pathlib.WindowsPath类型
#      这种类型的数据只能通过Path这个函数得到，
#   3、Path这个函数的参数是一个字符串，这个函数的返回值就是pathlib.WindowsPath类型的数据
import json

numbers = [2, 3, 5, 7, 11, 13]

path = Path('numbers.json')  # 选择一个文件名，指定要将该数值列表存储在哪个文件中
                             # 通常使用文件扩展名.json来指出文件存储的数据为JSON
print(type(path))
contents = json.dumps(numbers)  # 使用json.dumps()函数生成一个字符串，
                                # 字符串包含我们要存储的数据的JSON格式
print(type(contents))
path.write_text(contents)  # 使用write_test()方法将上一句中的字符串写入文件

# 10.4.1-2w
# 下面的程序完成了：
# 使用json.loads()将上述的数值列表读取到内存中
# 默认已经写入from pathlib import Path 和 import json 这两句话
"""
path = Path('username.json')
if path.exists():
    contents = path.read_text()
    username = json.loads(contents)
    print(f"Welcome back, {username}!")
else:
    username = input('What is your name? ')
    contents = json.dumps(username)
    path.write_text(contents)
    print(f"We will remember you when you come back, {username}!")
"""

# 10.4.3
# 对10.4.2中的代码进行重构，把代码分成多个函数来执行
# 将原函数分成两个部分：
# 1. 如果本地之前就存储了用户名，则执行get_stored_username，获得文件中的用户名
# 2. 如果本地之前没有存储用户名，则执行get_new_username，将用户名存到本地
"""
def get_stored_username(path):
    if path.exists():
        contents = path.read_text()
        username = json.loads(contents)
        return username
    else:
        return None


def get_new_username(path):
    username = input("What is your name?")
    contents = json.dumps(username)
    path.write_text(contents)
    return username


def greet_user():
    path = Path('username.json')
    username = get_stored_username(path)
    if username:
        print(f"Welcome back, {username}!")
    else:
        username = get_new_username(path)
        print(f"We will remember you when you come back, {username}!")
"""

# greet_user()


# 10.4后面的动手试一试
# 练习10.11
"""
path = Path('favorite_number.json')
favorite_number = input("Please write down your favorite number: ")
contents = json.dumps(favorite_number)
path.write_text(contents)

contents = path.read_text()
favorite_number = json.loads(contents)
print(f"I know your favorite number! It is {favorite_number}.")
"""

# 练习10.12
"""
path = Path('favorite_number.json')
if path.exists():
    contents = path.read_text()
    favorite_number = json.loads(contents)
    print(f"I have already known your favorite number! It is {favorite_number}")
else:
    favorite_number = input("Please write down your favorite number: ")
    contents = json.dumps(favorite_number)
    path.write_text(contents)
    print(f"I just knew your favorite number! It is {favorite_number}")
"""

# 练习10.13
"""
def build_profile(name, age, sex, **user_info):
    user_info['name'] = name.title()
    user_info['age'] = age
    user_info['sex'] = sex
    return user_info


user_name = input('Please write down your name: ')
user_age = input('Pleas write down your age: ')
user_sex = input('Please write down your sex: ')
user_profile = build_profile(user_name, user_age, user_sex)

path = Path('userinfo.json')
contents = json.dumps(user_profile)
path.write_text(contents)

contents = path.read_text()
user_profile = json.loads(contents)
print(f"Your information have been recorded as follows:\n"
      f"Your name: {user_profile['name']}\n"
      f"Your age: {user_profile['age']}\n"
      f"Your sex: {user_profile['sex']}\n")
"""


# 练习10.14
def build_profile(name, age, sex, **user_info):
    user_info['name'] = name.title()
    user_info['age'] = age
    user_info['sex'] = sex
    return user_info


def get_stored_username(path):
    if path.exists():
        contents = path.read_text()
        user_info = json.loads(contents)
        return user_info
    else:
        return None


def print_userinfo(user_profile):
    print(f"Your information have been recorded as follows:\n"
          f"Your name: {user_profile['name']}\n"
          f"Your age: {user_profile['age']}\n"
          f"Your sex: {user_profile['sex']}\n")


def enter_userinfo():
    user_name = input('Please write down your name: ')
    user_age = input('Pleas write down your age: ')
    user_sex = input('Please write down your sex: ')
    user_profile = build_profile(user_name, user_age, user_sex)
    return user_profile


def get_new_userinfo(path):
    user_profile = enter_userinfo()
    contents = json.dumps(user_profile)
    path.write_text(contents)
    return user_profile


def greet_user():
    path = Path('userinfo.json')
    user_info = get_stored_username(path)
    if user_info:
        ret = input(f"We have already recorded someone's information, "
                    f"could you please enter Y or N to"
                    f" tell me if you are {user_info['name']}: ")
        if ret == 'Y':
            print(f"Welcome back, {user_info['name']}!")
        else:
            print(f"Sorry, we have made a mistake, please write down your information.")
            user_profile = get_new_userinfo(path)
            print(f"We will remember you when you come back!", end=' ')
            print_userinfo(user_profile)
    else:
        user_profile = get_new_userinfo(path)
        print(f"We will remember you when you come back, {user_profile['name']}!")
        print_userinfo(user_profile)


greet_user()


